Back to Article
Code Notebook 3.1
Download Source

Exploratory Analyses, Variable and Sample Descriptions

Authors
Affiliations

Tristan Muno

University of Mannheim

Thomas König

University of Mannheim

Published

January 16, 2026

Setup

In [1]:
Code

# To track render duration
start_time <- Sys.time()

# set width of console output
options(width = 80)


# Install and load required packages
p_required <- c(
  "tidyverse",
  "here",
  "janitor",
  "knitr",
  "dagitty",
  "ggdag",
  "ggpubr",
  "gtsummary",
  "gt",
  "scales",
  "sessioninfo"
)
packages <- rownames(installed.packages())
p_to_install <- p_required[!(p_required %in% packages)]
if (length(p_to_install) > 0) {
  install.packages(p_to_install)
}
sapply(p_required, require, character.only = TRUE)
Loading required package: tidyverse
── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
✔ dplyr     1.1.4     ✔ readr     2.1.6
✔ forcats   1.0.1     ✔ stringr   1.6.0
✔ ggplot2   4.0.1     ✔ tibble    3.3.1
✔ lubridate 1.9.4     ✔ tidyr     1.3.2
✔ purrr     1.2.1     
── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag()    masks stats::lag()
ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
Loading required package: here

here() starts at C:/R/research/CSAP

Loading required package: janitor


Attaching package: 'janitor'


The following objects are masked from 'package:stats':

    chisq.test, fisher.test


Loading required package: knitr

Loading required package: dagitty

Loading required package: ggdag


Attaching package: 'ggdag'


The following object is masked from 'package:stats':

    filter


Loading required package: ggpubr

Loading required package: gtsummary

Loading required package: gt

Loading required package: scales


Attaching package: 'scales'


The following object is masked from 'package:purrr':

    discard


The following object is masked from 'package:readr':

    col_factor


Loading required package: sessioninfo
  tidyverse        here     janitor       knitr     dagitty       ggdag 
       TRUE        TRUE        TRUE        TRUE        TRUE        TRUE 
     ggpubr   gtsummary          gt      scales sessioninfo 
       TRUE        TRUE        TRUE        TRUE        TRUE 
Code

rm(p_required, p_to_install, packages)
In [2]:
Code

eu25games2019 <- readRDS(
  file = here(
    "data",
    "03_final",
    "eu25games2019.rds"
  )
)

Distribution of implicit and explicit partisans pooled and across countries

In [3]:
Code

eu25games2019 |>
  tabyl(der_pid) |>
  adorn_totals() |>
  kable(
    digits = 2,
    booktabs = T
  )
In [4]:
Distribution of reported partisan attachement (explicit partisan identity) in the pooled sample.
der_pid n percent
Party ID reported 110142 0.62
No Party ID 65280 0.36
Other 3276 0.02
NA 238 0.00
Total 178936 1.00
In [5]:
Code

eu25games2019 |>
  tabyl(der_vote_cat) |>
  adorn_totals() |>
  kable(
    digits = 2,
    booktabs = T
  )
In [6]:
Distribution of reported vote intention and choice (implicit partisan identity) in the pooled sample.
der_vote_cat n percent
Vote reported 140384 0.78
Don’t know 29920 0.17
Other 8046 0.04
NA 586 0.00
Total 178936 1.00
In [7]:
Code

eu25games2019 |>
  tabyl(der_pid, der_vote_cat) |>
  adorn_totals() |>
  kable(
    digits = 2,
    booktabs = T
  )
In [8]:
Distribution of explicit and implicit partisan identities in the pooled sample.
der_pid Vote reported Don’t know Other NA
Party ID reported 101502 6180 2172 288
No Party ID 37404 23400 4398 78
Other 1464 336 1476 0
NA 14 4 0 220
Total 140384 29920 8046 586
In [9]:
Code

eu25games2019 |>
  tabyl(meta_country, der_pid) |>
  adorn_totals() |>
  kable(
    digits = 2,
    booktabs = T
  )
In [10]:
Distribution of reported partisan attachement (explicit partisan identity) by country.
meta_country Party ID reported No Party ID Other NA
Austria 3978 3600 78 6
Belgium 5292 2454 78 6
Bulgaria 2790 2916 180 6
Croatia 3786 3294 354 6
Czech Republic 4848 1866 84 12
Denmark 6006 1032 156 6
Estonia 3318 2256 78 12
Finland 4362 2418 174 6
France 4446 2454 18 18
Germany 4062 3000 66 0
Greece 4194 2304 462 6
Hungary 3834 1986 96 0
Ireland 3084 3192 84 6
Italy 5346 1602 66 18
Latvia 2676 4092 114 6
Lithuania 3348 4038 204 0
Netherlands 5028 2226 60 12
Poland 5190 1956 36 6
Portugal 4386 2574 144 10
Romania 4932 3744 168 18
Slovakia 4536 3114 132 0
Slovenia 4278 2376 120 36
Spain 5934 2274 156 12
Sweden 5622 1758 132 12
United Kingdom 4866 2754 36 18
Total 110142 65280 3276 238
In [11]:
Code

eu25games2019 |>
  tabyl(der_vote_cat, meta_country) |>
  adorn_totals() |>
  kable(
    digits = 2,
    booktabs = T
  )
In [12]:
Distribution of reported vote intention and choice (implicit partisan identity) in the pooled sample.
der_vote_cat Austria Belgium Bulgaria Croatia Czech Republic Denmark Estonia Finland France Germany Greece Hungary Ireland Italy Latvia Lithuania Netherlands Poland Portugal Romania Slovakia Slovenia Spain Sweden United Kingdom
Vote reported 6444 6498 4182 4548 5082 6174 4908 5412 5292 5436 5310 4824 4980 5592 5064 5994 5904 6222 4770 6992 5808 5076 7152 6288 6432
Don’t know 1098 1110 1104 1914 1518 858 396 1188 1386 1044 1182 882 1152 1272 1248 1332 1224 930 1738 1350 1668 1296 996 972 1062
Other 108 210 600 972 192 156 348 330 204 408 462 210 228 150 570 264 186 30 606 504 306 402 204 252 144
NA 12 12 6 6 18 12 12 30 54 240 12 0 6 18 6 0 12 6 0 16 0 36 24 12 36
Total 7662 7830 5892 7440 6810 7200 5664 6960 6936 7128 6966 5916 6366 7032 6888 7590 7326 7188 7114 8862 7782 6810 8376 7524 7674
Code

eu25games2019 |>
  tabyl(der_pid, der_vote_cat, meta_country) |>
  adorn_totals()
In [13]:
Distribution of explicit and implicit partisan identities by country.
$Austria
           der_pid Vote reported Don't know Other NA
 Party ID reported          3774        192     6  6
       No Party ID          2622        900    78  0
             Other            48          6    24  0
                NA             0          0     0  6
             Total          6444       1098   108 12

$Belgium
           der_pid Vote reported Don't know Other NA
 Party ID reported          5040        210    36  6
       No Party ID          1434        888   132  0
             Other            24         12    42  0
                NA             0          0     0  6
             Total          6498       1110   210 12

$Bulgaria
           der_pid Vote reported Don't know Other NA
 Party ID reported          2520        168   102  0
       No Party ID          1548        918   450  0
             Other           114         18    48  0
                NA             0          0     0  6
             Total          4182       1104   600  6

$Croatia
           der_pid Vote reported Don't know Other NA
 Party ID reported          3102        348   336  0
       No Party ID          1320       1554   420  0
             Other           126         12   216  0
                NA             0          0     0  6
             Total          4548       1914   972  6

$`Czech Republic`
           der_pid Vote reported Don't know Other NA
 Party ID reported          4236        546    60  6
       No Party ID           828        966    72  0
             Other            18          6    60  0
                NA             0          0     0 12
             Total          5082       1518   192 18

$Denmark
           der_pid Vote reported Don't know Other NA
 Party ID reported          5568        360    72  6
       No Party ID           540        444    48  0
             Other            66         54    36  0
                NA             0          0     0  6
             Total          6174        858   156 12

$Estonia
           der_pid Vote reported Don't know Other NA
 Party ID reported          3120         72   126  0
       No Party ID          1728        324   204  0
             Other            60          0    18  0
                NA             0          0     0 12
             Total          4908        396   348 12

$Finland
           der_pid Vote reported Don't know Other NA
 Party ID reported          4068        204    72 18
       No Party ID          1284        972   156  6
             Other            60         12   102  0
                NA             0          0     0  6
             Total          5412       1188   330 30

$France
           der_pid Vote reported Don't know Other NA
 Party ID reported          4176        180    54 36
       No Party ID          1110       1194   150  0
             Other             6         12     0  0
                NA             0          0     0 18
             Total          5292       1386   204 54

$Germany
           der_pid Vote reported Don't know Other  NA
 Party ID reported          3666         90   132 174
       No Party ID          1764        948   222  66
             Other             6          6    54   0
                NA             0          0     0   0
             Total          5436       1044   408 240

$Greece
           der_pid Vote reported Don't know Other NA
 Party ID reported          3894        222    72  6
       No Party ID          1194        912   198  0
             Other           222         48   192  0
                NA             0          0     0  6
             Total          5310       1182   462 12

$Hungary
           der_pid Vote reported Don't know Other NA
 Party ID reported          3642        168    24  0
       No Party ID          1134        708   144  0
             Other            48          6    42  0
                NA             0          0     0  0
             Total          4824        882   210  0

$Ireland
           der_pid Vote reported Don't know Other NA
 Party ID reported          2916        120    48  0
       No Party ID          2016       1032   144  0
             Other            48          0    36  0
                NA             0          0     0  6
             Total          4980       1152   228  6

$Italy
           der_pid Vote reported Don't know Other NA
 Party ID reported          4950        366    30  0
       No Party ID           618        900    84  0
             Other            24          6    36  0
                NA             0          0     0 18
             Total          5592       1272   150 18

$Latvia
           der_pid Vote reported Don't know Other NA
 Party ID reported          2346        174   156  0
       No Party ID          2652       1062   378  0
             Other            66         12    36  0
                NA             0          0     0  6
             Total          5064       1248   570  6

$Lithuania
           der_pid Vote reported Don't know Other NA
 Party ID reported          3132        192    24  0
       No Party ID          2724       1122   192  0
             Other           138         18    48  0
                NA             0          0     0  0
             Total          5994       1332   264  0

$Netherlands
           der_pid Vote reported Don't know Other NA
 Party ID reported          4704        270    54  0
       No Party ID          1182        948    96  0
             Other            18          6    36  0
                NA             0          0     0 12
             Total          5904       1224   186 12

$Poland
           der_pid Vote reported Don't know Other NA
 Party ID reported          4950        240     0  0
       No Party ID          1242        690    24  0
             Other            30          0     6  0
                NA             0          0     0  6
             Total          6222        930    30  6

$Portugal
           der_pid Vote reported Don't know Other NA
 Party ID reported          3672        498   216  0
       No Party ID          1068       1218   288  0
             Other            24         18   102  0
                NA             6          4     0  0
             Total          4770       1738   606  0

$Romania
           der_pid Vote reported Don't know Other NA
 Party ID reported          4614        186   126  6
       No Party ID          2316       1128   300  0
             Other            54         36    78  0
                NA             8          0     0 10
             Total          6992       1350   504 16

$Slovakia
           der_pid Vote reported Don't know Other NA
 Party ID reported          4104        306   126  0
       No Party ID          1632       1350   132  0
             Other            72         12    48  0
                NA             0          0     0  0
             Total          5808       1668   306  0

$Slovenia
           der_pid Vote reported Don't know Other NA
 Party ID reported          3798        348   132  0
       No Party ID          1224        942   210  0
             Other            54          6    60  0
                NA             0          0     0 36
             Total          5076       1296   402 36

$Spain
           der_pid Vote reported Don't know Other NA
 Party ID reported          5688        186    54  6
       No Party ID          1386        786    96  6
             Other            78         24    54  0
                NA             0          0     0 12
             Total          7152        996   204 24

$Sweden
           der_pid Vote reported Don't know Other NA
 Party ID reported          5274        270    78  0
       No Party ID           966        696    96  0
             Other            48          6    78  0
                NA             0          0     0 12
             Total          6288        972   252 12

$`United Kingdom`
           der_pid Vote reported Don't know Other NA
 Party ID reported          4548        264    36 18
       No Party ID          1872        798    84  0
             Other            12          0    24  0
                NA             0          0     0 18
             Total          6432       1062   144 36

Overview of data distribution

Respondents -> Party ID -> Vote report

In words, respondents either report a partisan identity (i.e., a felt attachement to a political party) or they deny the presence of such feelings.

The number of respondents

Code

eu25games2019 |>
  distinct(meta_pid) |>
  nrow()
In [14]:
[1] 29827

The numer of respondents reporting PID vs not

Code

eu25games2019 |>
  distinct(meta_pid, .keep_all = T) |>
  count(der_pid)
In [15]:
# A tibble: 4 × 2
  der_pid               n
  <fct>             <int>
1 Party ID reported 18357
2 No Party ID       10880
3 Other               546
4 NA                   44

The number of non-identifiers who report a vote (vs not)

Code

eu25games2019 |>
  distinct(meta_pid, .keep_all = T) |>
  filter(der_pid == "No Party ID") |>
  count(der_vote_cat)
In [16]:
# A tibble: 4 × 2
  der_vote_cat      n
  <fct>         <int>
1 Vote reported  6234
2 Don't know     3900
3 Other           733
4 NA               13

The number of identifiers who report a vote (vs not)

Code

eu25games2019 |>
  distinct(meta_pid, .keep_all = T) |>
  filter(der_pid == "Party ID reported") |>
  count(der_vote_cat)
In [17]:
# A tibble: 4 × 2
  der_vote_cat      n
  <fct>         <int>
1 Vote reported 16917
2 Don't know     1030
3 Other           362
4 NA               48

The number of identifiers who reported vote identical to PID

Code

eu25games2019 |>
  distinct(meta_pid, .keep_all = T) |>
  filter(der_pid == "Party ID reported") |>
  mutate(
    pid_equal_vote_name = if_else(
      der_vote_combined_name == ext_q_party_id_pf_name,
      1,
      0
    )
  ) |>
  count(pid_equal_vote_name)
Code

# but accounting for unknown and dont-know answers yields
eu25games2019 |>
  distinct(meta_pid, .keep_all = T) |>
  filter(
    der_pid == "Party ID reported",
    der_vote_combined_name != "unknown",
    der_vote_combined_name != "dont-know"
  ) |>
  mutate(
    pid_equal_vote_name = if_else(
      der_vote_combined_name == ext_q_party_id_pf_name,
      1,
      0
    ),
    pid_equal_vote_id = if_else(
      der_vote_combined_id == ext_q_party_id_pf_id,
      1,
      0
    )
  ) |>
  count(pid_equal_vote_name, pid_equal_vote_id)
In [18]:
# A tibble: 3 × 2
  pid_equal_vote_name     n
                <dbl> <int>
1                   0  5858
2                   1 12451
3                  NA    48
# A tibble: 4 × 3
  pid_equal_vote_name pid_equal_vote_id     n
                <dbl>             <dbl> <int>
1                   0                 0  3626
2                   0                NA  1202
3                   1                 1 12437
4                   1                NA    14
Code

eu25games2019 |>
  distinct(meta_pid, .keep_all = T) |>
  filter(der_pid == "Party ID reported") |>
  mutate(
    pid_equal_vote_id = if_else(
      der_vote_combined_id == ext_q_party_id_pf_id,
      1,
      0
    )
  ) |>
  count(pid_equal_vote_id)
In [19]:
# A tibble: 3 × 2
  pid_equal_vote_id     n
              <dbl> <int>
1                 0  3626
2                 1 12437
3                NA  2294
In [20]:
Code
eu25games2019 <- eu25games2019 |>
  mutate(
    pid_equal_vote_id = case_when(
      der_pid == "Party ID reported" &
        der_vote_cat == "Vote reported" &
        der_vote_combined_id == ext_q_party_id_pf_id ~ 1,
      der_pid == "Party ID reported" &
        der_vote_cat == "Vote reported" &
        der_vote_combined_id != ext_q_party_id_pf_id ~ 0,
      .default = NA
    ),
    pid_equal_vote_name = case_when(
      der_pid == "Party ID reported" &
        der_vote_cat == "Vote reported" &
        der_vote_combined_name == ext_q_party_id_pf_name ~ 1,
      der_pid == "Party ID reported" &
        der_vote_cat == "Vote reported" &
        der_vote_combined_name != ext_q_party_id_pf_name ~ 0,
      .default = NA
    )
  )

# manually recode some instances where the casewhen check above yielded different but inspection revealed its basically the same party
eu25games2019 <- eu25games2019 |>
  mutate(
    # New column using case_when for manual line-by-line recoding
    pid_equal_vote_name2 = case_when(
      # Case 1: Party names are already identical (from pid_equal_vote_name = 1)
      pid_equal_vote_name == 1 ~ 1,

      # Case 2: Polish Koalicja Obywatelska (PO, SLD, Spring, PSL, Nowoczesna)
      pid_equal_vote_name == 0 &
        ext_q_party_id_pf_name %in%
          c(
            "Platforma Obywatelska",
            "Sojusz Lewicy Demokratycznej",
            "Spring",
            "Polskie Stronnictwo Ludowe",
            "Nowoczesna"
          ) &
        der_vote_combined_name == "Koalicja Obywatelska" ~ 1,

      # Case 3: Spanish Unidas Podemos (Podemos, Izquierda Unida)
      pid_equal_vote_name == 0 &
        ext_q_party_id_pf_name %in%
          c(
            "Podemos",
            "Izquierda Unida"
          ) &
        der_vote_combined_name == "Unidas Podemos" ~ 1,

      # Case 4: Dutch ChristenUnie — SGP
      pid_equal_vote_name == 0 &
        ext_q_party_id_pf_name %in%
          c(
            "ChristenUnie",
            "Staatkundig Gereformeerde Partij"
          ) &
        der_vote_combined_name ==
          "ChristenUnie — Staatkundig Gereformeerde Partij" ~ 1,

      # Case 5: Hungarian Fidesz — KDNP (using grepl for robustness against long name)
      pid_equal_vote_name == 0 &
        ext_q_party_id_pf_name %in%
          c(
            "Fidesz — Magyar Polgári Szövetség",
            "Kereszténydemokrata Néppárt"
          ) &
        grepl(
          "Fidesz — KDNP pártszövetség",
          der_vote_combined_name,
          fixed = TRUE
        ) ~ 1,

      # Case 6: Polish Konfederacja Wolność i Niepodległość (KNP, KORWiN, Kukiz'15)
      pid_equal_vote_name == 0 &
        ext_q_party_id_pf_name %in%
          c(
            "Kongres Nowej Prawicy",
            "Koalicja Odnowy Rzeczypospolitej Wolność i Nadzieja KORWiN",
            "Kukiz'15"
          ) &
        der_vote_combined_name == "Konfederacja Wolność i Niepodległość" ~ 1,

      # Case 7: Latvian Attīstībai/Par!
      pid_equal_vote_name == 0 &
        ext_q_party_id_pf_name == "Kustība Par!" &
        der_vote_combined_name == "Attīstībai/Par!" ~ 1,

      # Case 8: French LREM/Renaissance
      pid_equal_vote_name == 0 &
        ext_q_party_id_pf_name == "Mouvement démocrate" &
        der_vote_combined_name == "La République En Marche! / Renaissance" ~ 1,

      # Case 9: Catalan JxCat (Partit Demòcrata Europeu Català)
      pid_equal_vote_name == 0 &
        ext_q_party_id_pf_name == "Partit Demòcrata Europeu Català" &
        der_vote_combined_name ==
          "Junts per Catalunya — Partit Demòcrata Europeu Català" ~ 1,

      # Default: All other cases (where pid_equal_vote_name was 0 and no manual case matched)
      TRUE ~ pid_equal_vote_name
    )
  )

eu25games2019 |>
  distinct(meta_pid, .keep_all = T) |>
  count(pid_equal_vote_name2)
# A tibble: 3 × 2
  pid_equal_vote_name2     n
                 <dbl> <int>
1                    0  3697
2                    1 13220
3                   NA 12910

Schematic overview

In [21]:
Code
flowchart TD
    A(Respondents <br> N = 29,827) --> B(No Party ID <br> N = 10,880) 
    A(Respondents <br> N = 29,827) --> C(Party ID <br> N = 18,357)

    B --> D(No Vote <br> N = 3,900)
    B --> E(Vote <br> N = 6,234)

    C --> F(No Vote <br> N = 1,030)
    C --> G(Vote <br> N = 16,917)

    G --> H(Same as PID <br> N = 13,220)
    G --> I(Diff from PID <br> N = 3,697)

flowchart TD
    A(Respondents <br> N = 29,827) --> B(No Party ID <br> N = 10,880) 
    A(Respondents <br> N = 29,827) --> C(Party ID <br> N = 18,357)

    B --> D(No Vote <br> N = 3,900)
    B --> E(Vote <br> N = 6,234)

    C --> F(No Vote <br> N = 1,030)
    C --> G(Vote <br> N = 16,917)

    G --> H(Same as PID <br> N = 13,220)
    G --> I(Diff from PID <br> N = 3,697)

Figures

In [22]:
Code

df_reshaped <- eu25games2019 |>
  group_by(meta_country, der_nopid, der_vote_cat) |>
  count() |>
  ungroup()

df_reshaped
# A tibble: 179 × 4
   meta_country der_nopid der_vote_cat      n
   <chr>            <dbl> <fct>         <int>
 1 Austria              0 Vote reported  3822
 2 Austria              0 Don't know      198
 3 Austria              0 Other            30
 4 Austria              0 NA                6
 5 Austria              1 Vote reported  2622
 6 Austria              1 Don't know      900
 7 Austria              1 Other            78
 8 Austria              1 NA                6
 9 Belgium              0 Vote reported  5064
10 Belgium              0 Don't know      222
# ℹ 169 more rows
Code

total_counts <- df_reshaped |>
  group_by(meta_country, der_nopid) |>
  summarise(n = sum(n), .groups = "drop") |>
  mutate(
    nopid2 = if_else(der_nopid == 1, "No PID", "PID"),
    toprint = paste0(
      nopid2,
      "\n",
      as.character(n)
    ),
    toprint2 = as.character(n)
  )

ggplot(df_reshaped, aes(x = as.factor(der_nopid), y = n, fill = der_vote_cat)) +
  geom_col() +
  geom_text(
    data = total_counts,
    aes(label = toprint2, fill = "black"),
    vjust = if_else(
      total_counts$der_nopid == 1,
      0,
      1
    ),
    size = 3
  ) +
  facet_wrap(~meta_country) +
  labs(y = "N", x = "") +
  scale_x_discrete(labels = c("0" = "PID", "1" = "No PID")) +
  scale_fill_manual(
    values = c(
      "Don't know" = "darkgray",
      "NA" = "black",
      "Other" = "orange",
      "Vote reported" = "gold"
    )
  ) +
  theme_pubr()
Warning in geom_text(data = total_counts, aes(label = toprint2, fill =
"black"), : Ignoring unknown aesthetics: fill
Distribution of Reported Partisan Affiliation and Vote Choice/Intention across included European countries.

Implicit vs explicit partisans distributions

In [23]:
Code

toplot <- eu25games2019 |>
  select(meta_country, der_partisanship, meta_pid) |>
  distinct(meta_pid, .keep_all = T) |>
  filter(!is.na(der_partisanship)) |>
  group_by(meta_country) |>
  count(der_partisanship) |>
  mutate(
    total_n = sum(n),
    prop = n / total_n
  ) |>
  ungroup()

expl_prop <- toplot |>
  filter(der_partisanship == "1_pid_expl") |>
  select(meta_country, expl_prop = prop)

toplot <- toplot |>
  left_join(
    expl_prop,
    by = join_by(meta_country)
  ) |>
  mutate(
    meta_country = fct_reorder(meta_country, expl_prop),
    der_partisanship2 = case_when(
      der_partisanship == "1_pid_expl" ~ "Explicit",
      der_partisanship == "2_pid_impl" ~ "Implicit",
      der_partisanship == "3_nopid" ~ "None"
    )
  )

ggplot(
  toplot,
  aes(x = n, y = meta_country, fill = der_partisanship2)
) +
  geom_bar(
    stat = "identity",
    position = "fill",
    color = "black",
    width = 0.75
  ) +
  scale_fill_manual(
    values = c("white", "#CCCCCC", "black"),
    labels = c(
      bquote("Explicit (" * italic(T)[i] == 1 * ")"),
      bquote("Implicit (" * italic(T)[i] == 0 * ")"),
      expression(paste("None (", italic(T)[i] == phantom(0) * "\u2205", ")"))
    )
  ) +
  scale_x_continuous(labels = percent) +
  labs(
    x = "Share",
    y = "Country",
    fill = bquote("Partisan Type (" * italic(T)[i] * ")")
  ) +
  theme_pubr() +
  theme(
    aspect.ratio = 1 / 1.618034
  )
Distribution of partisan types, by country. Stacked horizontal bars show the within-country share (%) of three partisan types: explicit partisans (respondents who reported a subjective attachement to a party, \(T_i=1\)), implicit partisans (respondents who reported no attachement but did report a vote preference or intention, \(T_i=0\)), and respondents who reported neither (none, \(T_i = \emptyset\)). Percentages sum to 100% within each country, with country samples containing about \(1,100\) respondents each (detailed numbers are reported in appendix section X).

Exploratory analysis of country specific ingroup and outgroup dynamics by partisan type

In [24]:
Code

eu25games2019 <- eu25games2019 |>
  mutate(
    cj_token_logged = log(cj_token + 1)
  )

token_means <- eu25games2019 |>
  filter(meta_game == "dict") |>
  filter(
    !der_outpartisan_comb %in%
      c(
        "97_eunat_expl",
        "97_eunat_impl",
        "98_outnat_expl",
        "98_outnat_impl",
        "99_outnatEU_nopid",
        "99_outnat_nopid"
      ) &
      !is.na(der_outpartisan_comb)
  ) |>
  group_by(meta_country, der_outpartisan_comb) |>
  summarise(
    m = mean(cj_token_logged),
    s = sd(cj_token_logged),
    n = n()
  ) |>
  ungroup()
`summarise()` has grouped output by 'meta_country'. You can override using the
`.groups` argument.
Code

token_means_pooled <- eu25games2019 |>
  filter(meta_game == "dict") |>
  filter(
    !der_outpartisan_comb %in%
      c(
        "97_eunat_expl",
        "97_eunat_impl",
        "98_outnat_expl",
        "98_outnat_impl",
        "99_outnatEU_nopid",
        "99_outnat_nopid"
      ) &
      !is.na(der_outpartisan_comb)
  ) |>
  group_by(der_outpartisan_comb) |>
  summarise(
    m = mean(cj_token_logged),
    s = sd(cj_token_logged),
    n = n()
  ) |>
  ungroup()

token_means_pooled <- token_means_pooled |>
  mutate(meta_country = "Pooled") |>
  select(meta_country, der_outpartisan_comb, m, s, n)

token_means <- token_means |>
  bind_rows(token_means_pooled)


qoi_bycountry <- token_means |>
  group_by(meta_country) |>
  summarise(
    # Explicit Conditions (expl_Type_Stat)

    # IF_expl: Difference (2 - 1)
    expl_IF_diff = m[der_outpartisan_comb == "2_co_expl"] -
      m[der_outpartisan_comb == "1_control_expl"],
    expl_IF_SE = sqrt(
      (s[der_outpartisan_comb == "2_co_expl"]^2 /
        n[der_outpartisan_comb == "2_co_expl"]) +
        (s[der_outpartisan_comb == "1_control_expl"]^2 /
          n[der_outpartisan_comb == "1_control_expl"])
    ),
    expl_IF_CI_LOWER = expl_IF_diff - 1.96 * expl_IF_SE,
    expl_IF_CI_UPPER = expl_IF_diff + 1.96 * expl_IF_SE,

    # OD_expl: Difference (1 - 3)
    expl_OD_diff = m[der_outpartisan_comb == "1_control_expl"] -
      m[der_outpartisan_comb == "3_out_expl"],
    expl_OD_SE = sqrt(
      (s[der_outpartisan_comb == "1_control_expl"]^2 /
        n[der_outpartisan_comb == "1_control_expl"]) +
        (s[der_outpartisan_comb == "3_out_expl"]^2 /
          n[der_outpartisan_comb == "3_out_expl"])
    ),
    expl_OD_CI_LOWER = expl_OD_diff - 1.96 * expl_OD_SE,
    expl_OD_CI_UPPER = expl_OD_diff + 1.96 * expl_OD_SE,

    # AP_expl: Difference (2 - 3)
    expl_AP_diff = m[der_outpartisan_comb == "2_co_expl"] -
      m[der_outpartisan_comb == "3_out_expl"],
    expl_AP_SE = sqrt(
      (s[der_outpartisan_comb == "2_co_expl"]^2 /
        n[der_outpartisan_comb == "2_co_expl"]) +
        (s[der_outpartisan_comb == "3_out_expl"]^2 /
          n[der_outpartisan_comb == "3_out_expl"])
    ),
    expl_AP_CI_LOWER = expl_AP_diff - 1.96 * expl_AP_SE,
    expl_AP_CI_UPPER = expl_AP_diff + 1.96 * expl_AP_SE,

    # Implicit Conditions (impl_Type_Stat)

    # IF_impl: Difference (5 - 4)
    impl_IF_diff = m[der_outpartisan_comb == "5_co_impl"] -
      m[der_outpartisan_comb == "4_control_impl"],
    impl_IF_SE = sqrt(
      (s[der_outpartisan_comb == "5_co_impl"]^2 /
        n[der_outpartisan_comb == "5_co_impl"]) +
        (s[der_outpartisan_comb == "4_control_impl"]^2 /
          n[der_outpartisan_comb == "4_control_impl"])
    ),
    impl_IF_CI_LOWER = impl_IF_diff - 1.96 * impl_IF_SE,
    impl_IF_CI_UPPER = impl_IF_diff + 1.96 * impl_IF_SE,

    # OD_impl: Difference (4 - 6)
    impl_OD_diff = m[der_outpartisan_comb == "4_control_impl"] -
      m[der_outpartisan_comb == "6_out_impl"],
    impl_OD_SE = sqrt(
      (s[der_outpartisan_comb == "4_control_impl"]^2 /
        n[der_outpartisan_comb == "4_control_impl"]) +
        (s[der_outpartisan_comb == "6_out_impl"]^2 /
          n[der_outpartisan_comb == "6_out_impl"])
    ),
    impl_OD_CI_LOWER = impl_OD_diff - 1.96 * impl_OD_SE,
    impl_OD_CI_UPPER = impl_OD_diff + 1.96 * impl_OD_SE,

    # AP_impl: Difference (5 - 6)
    impl_AP_diff = m[der_outpartisan_comb == "5_co_impl"] -
      m[der_outpartisan_comb == "6_out_impl"],
    impl_AP_SE = sqrt(
      (s[der_outpartisan_comb == "5_co_impl"]^2 /
        n[der_outpartisan_comb == "5_co_impl"]) +
        (s[der_outpartisan_comb == "6_out_impl"]^2 /
          n[der_outpartisan_comb == "6_out_impl"])
    ),
    impl_AP_CI_LOWER = impl_AP_diff - 1.96 * impl_AP_SE,
    impl_AP_CI_UPPER = impl_AP_diff + 1.96 * impl_AP_SE,

    # None Condition (none_Type_Stat)

    # OD_none: Difference (7 - 8)
    none_OD_diff = m[der_outpartisan_comb == "7_control_nopid"] -
      m[der_outpartisan_comb == "8_ptycue_nopid"],
    none_OD_SE = sqrt(
      (s[der_outpartisan_comb == "7_control_nopid"]^2 /
        n[der_outpartisan_comb == "7_control_nopid"]) +
        (s[der_outpartisan_comb == "8_ptycue_nopid"]^2 /
          n[der_outpartisan_comb == "8_ptycue_nopid"])
    ),
    none_OD_CI_LOWER = none_OD_diff - 1.96 * none_OD_SE,
    none_OD_CI_UPPER = none_OD_diff + 1.96 * none_OD_SE
  )


tidy_qoi <- qoi_bycountry |>
  # 1. Pivot the data from wide to long format
  pivot_longer(
    # Select all columns except the grouping variable
    cols = -meta_country,

    # 2. Split the column names into three parts: Condition, Type, and Value
    names_to = c("pid_type_raw", "diff_type", ".value"),

    # 3. Define the pattern for separation (Condition_Type_Statistic)
    names_pattern = "(expl|impl|none)_([A-Z]+)_(diff|SE|CI_LOWER|CI_UPPER)$"
    # Explanation:
    # (expl|impl|none) -> Captures the Condition into 'pid_type_raw'
    # ([A-Z]+)         -> Captures the Type (IF, OD, AP) into 'diff_type'
    # (diff|SE|CI_LOWER|CI_UPPER) -> Captures the Statistic into '.value' (creating columns diff, SE, CI_LOWER, CI_UPPER)
  ) |>

  # 4. Clean up the pid_type and rename the 'diff' column
  mutate(
    pid_type = case_match(
      pid_type_raw,
      "expl" ~ "explicit",
      "impl" ~ "implicit",
      "none" ~ "none"
    )
  ) |>
  rename(
    Difference = diff
  ) |>

  # 5. Select and reorder final columns for readability
  select(
    meta_country,
    pid_type,
    diff_type,
    Difference,
    SE,
    starts_with("CI_")
  )


plot_data <- tidy_qoi |>
  mutate(
    country_condition = paste(meta_country, pid_type, sep = " | "),
    country_condition = fct_inorder(country_condition)
  ) |>
  mutate(
    # extract pooled levels
    country_condition = fct_relevel(
      country_condition,
      grep("^Pooled \\|", levels(country_condition), value = TRUE),
      after = Inf # use 0 for top, Inf for bottom
    ),
    country_condition = fct_rev(country_condition),
    diff_type = factor(diff_type, levels = c("IF", "OD", "AP"))
  )


# 2. Create the Plot
ggplot(
  plot_data,
  aes(
    y = country_condition,
    x = Difference,
    shape = pid_type,
    color = meta_country
  )
) +

  # Add the vertical line at zero (to check for significance)
  geom_vline(xintercept = 0, linetype = "dashed", color = "red", alpha = 0.6) +

  # Add the Confidence Intervals (horizontal error bars)
  geom_errorbarh(
    aes(xmin = CI_LOWER, xmax = CI_UPPER),
    height = 0.2,
    linewidth = 0.5
  ) +

  # Add the point estimate
  geom_point(size = 2.5) +

  # Crucial Step: Facet the plot horizontally by the Difference Type (IF, OD, AP)
  facet_wrap(
    ~diff_type,
    ncol = 3,
    scales = "free_x" # Allow x-axis to scale independently for each difference type
  ) +

  # Labels and theming
  labs(
    y = "Country | PID Type",
    x = "Mean Difference (Point Estimate with 95% CI)"
  ) +
  theme_pubr() +
  scale_color_manual(
    values = c(
      rep(
        c(
          "#648FFF",
          "#DC267F",
          "#785EF0",
          "#FE6100",
          "#FFB000"
        ),
        5
      ),
      "black"
    )
  ) +
  theme(
    # Reduce font size for Y-axis labels if they are too long
    axis.text.y = element_text(size = 8, hjust = 0),
    # Ensure facet titles are clear
    strip.text = element_text(face = "bold"),
    legend.position = "none"
  )
Warning: `geom_errorbarh()` was deprecated in ggplot2 4.0.0.
ℹ Please use the `orientation` argument of `geom_errorbar()` instead.
`height` was translated to `width`.
Exploratory token allocation behavior by country and pid type in the dictator game: ingroup favoritism, outgroup derogation and affective polarization. The figure shows mean differences in token allocation with 95% confidence intervals. IF = mean(token2co) - mean(token2control), OD = mean(token2control) - mean(token2out), AP = mean(token2co) - mean(token2out)
In [25]:
Code

eu25games2019 <- eu25games2019 |>
  mutate(
    cj_token_logged = log(cj_token + 1)
  )

token_means <- eu25games2019 |>
  filter(meta_game == "trust") |>
  filter(
    !der_outpartisan_comb %in%
      c(
        "97_eunat_expl",
        "97_eunat_impl",
        "98_outnat_expl",
        "98_outnat_impl",
        "99_outnatEU_nopid",
        "99_outnat_nopid"
      ) &
      !is.na(der_outpartisan_comb)
  ) |>
  group_by(meta_country, der_outpartisan_comb) |>
  summarise(
    m = mean(cj_token_logged),
    s = sd(cj_token_logged),
    n = n()
  ) |>
  ungroup()
`summarise()` has grouped output by 'meta_country'. You can override using the
`.groups` argument.
Code

qoi_bycountry <- token_means |>
  group_by(meta_country) |>
  summarise(
    # Explicit Conditions (expl_Type_Stat)

    # IF_expl: Difference (2 - 1)
    expl_IF_diff = m[der_outpartisan_comb == "2_co_expl"] -
      m[der_outpartisan_comb == "1_control_expl"],
    expl_IF_SE = sqrt(
      (s[der_outpartisan_comb == "2_co_expl"]^2 /
        n[der_outpartisan_comb == "2_co_expl"]) +
        (s[der_outpartisan_comb == "1_control_expl"]^2 /
          n[der_outpartisan_comb == "1_control_expl"])
    ),
    expl_IF_CI_LOWER = expl_IF_diff - 1.96 * expl_IF_SE,
    expl_IF_CI_UPPER = expl_IF_diff + 1.96 * expl_IF_SE,

    # OD_expl: Difference (1 - 3)
    expl_OD_diff = m[der_outpartisan_comb == "1_control_expl"] -
      m[der_outpartisan_comb == "3_out_expl"],
    expl_OD_SE = sqrt(
      (s[der_outpartisan_comb == "1_control_expl"]^2 /
        n[der_outpartisan_comb == "1_control_expl"]) +
        (s[der_outpartisan_comb == "3_out_expl"]^2 /
          n[der_outpartisan_comb == "3_out_expl"])
    ),
    expl_OD_CI_LOWER = expl_OD_diff - 1.96 * expl_OD_SE,
    expl_OD_CI_UPPER = expl_OD_diff + 1.96 * expl_OD_SE,

    # AP_expl: Difference (2 - 3)
    expl_AP_diff = m[der_outpartisan_comb == "2_co_expl"] -
      m[der_outpartisan_comb == "3_out_expl"],
    expl_AP_SE = sqrt(
      (s[der_outpartisan_comb == "2_co_expl"]^2 /
        n[der_outpartisan_comb == "2_co_expl"]) +
        (s[der_outpartisan_comb == "3_out_expl"]^2 /
          n[der_outpartisan_comb == "3_out_expl"])
    ),
    expl_AP_CI_LOWER = expl_AP_diff - 1.96 * expl_AP_SE,
    expl_AP_CI_UPPER = expl_AP_diff + 1.96 * expl_AP_SE,

    # Implicit Conditions (impl_Type_Stat)

    # IF_impl: Difference (5 - 4)
    impl_IF_diff = m[der_outpartisan_comb == "5_co_impl"] -
      m[der_outpartisan_comb == "4_control_impl"],
    impl_IF_SE = sqrt(
      (s[der_outpartisan_comb == "5_co_impl"]^2 /
        n[der_outpartisan_comb == "5_co_impl"]) +
        (s[der_outpartisan_comb == "4_control_impl"]^2 /
          n[der_outpartisan_comb == "4_control_impl"])
    ),
    impl_IF_CI_LOWER = impl_IF_diff - 1.96 * impl_IF_SE,
    impl_IF_CI_UPPER = impl_IF_diff + 1.96 * impl_IF_SE,

    # OD_impl: Difference (4 - 6)
    impl_OD_diff = m[der_outpartisan_comb == "4_control_impl"] -
      m[der_outpartisan_comb == "6_out_impl"],
    impl_OD_SE = sqrt(
      (s[der_outpartisan_comb == "4_control_impl"]^2 /
        n[der_outpartisan_comb == "4_control_impl"]) +
        (s[der_outpartisan_comb == "6_out_impl"]^2 /
          n[der_outpartisan_comb == "6_out_impl"])
    ),
    impl_OD_CI_LOWER = impl_OD_diff - 1.96 * impl_OD_SE,
    impl_OD_CI_UPPER = impl_OD_diff + 1.96 * impl_OD_SE,

    # AP_impl: Difference (5 - 6)
    impl_AP_diff = m[der_outpartisan_comb == "5_co_impl"] -
      m[der_outpartisan_comb == "6_out_impl"],
    impl_AP_SE = sqrt(
      (s[der_outpartisan_comb == "5_co_impl"]^2 /
        n[der_outpartisan_comb == "5_co_impl"]) +
        (s[der_outpartisan_comb == "6_out_impl"]^2 /
          n[der_outpartisan_comb == "6_out_impl"])
    ),
    impl_AP_CI_LOWER = impl_AP_diff - 1.96 * impl_AP_SE,
    impl_AP_CI_UPPER = impl_AP_diff + 1.96 * impl_AP_SE,

    # None Condition (none_Type_Stat)

    # OD_none: Difference (7 - 8)
    none_OD_diff = m[der_outpartisan_comb == "7_control_nopid"] -
      m[der_outpartisan_comb == "8_ptycue_nopid"],
    none_OD_SE = sqrt(
      (s[der_outpartisan_comb == "7_control_nopid"]^2 /
        n[der_outpartisan_comb == "7_control_nopid"]) +
        (s[der_outpartisan_comb == "8_ptycue_nopid"]^2 /
          n[der_outpartisan_comb == "8_ptycue_nopid"])
    ),
    none_OD_CI_LOWER = none_OD_diff - 1.96 * none_OD_SE,
    none_OD_CI_UPPER = none_OD_diff + 1.96 * none_OD_SE
  )


tidy_qoi <- qoi_bycountry |>
  # 1. Pivot the data from wide to long format
  pivot_longer(
    # Select all columns except the grouping variable
    cols = -meta_country,

    # 2. Split the column names into three parts: Condition, Type, and Value
    names_to = c("pid_type_raw", "diff_type", ".value"),

    # 3. Define the pattern for separation (Condition_Type_Statistic)
    names_pattern = "(expl|impl|none)_([A-Z]+)_(diff|SE|CI_LOWER|CI_UPPER)$"
    # Explanation:
    # (expl|impl|none) -> Captures the Condition into 'pid_type_raw'
    # ([A-Z]+)         -> Captures the Type (IF, OD, AP) into 'diff_type'
    # (diff|SE|CI_LOWER|CI_UPPER) -> Captures the Statistic into '.value' (creating columns diff, SE, CI_LOWER, CI_UPPER)
  ) |>

  # 4. Clean up the pid_type and rename the 'diff' column
  mutate(
    pid_type = case_match(
      pid_type_raw,
      "expl" ~ "explicit",
      "impl" ~ "implicit",
      "none" ~ "none"
    )
  ) |>
  rename(
    Difference = diff
  ) |>

  # 5. Select and reorder final columns for readability
  select(
    meta_country,
    pid_type,
    diff_type,
    Difference,
    SE,
    starts_with("CI_")
  )

# 1. Prepare the data for plotting
plot_data <- tidy_qoi |>
  # Create a single factor combining country and condition for the Y-axis
  mutate(
    # Combine country and pid_type into one label (e.g., "Austria | explicit")
    country_condition = factor(paste(meta_country, pid_type, sep = " | ")),

    # Use fct_inorder to maintain the logical order (country-by-country)
    # Then fct_rev reverses the entire factor so the first country appears at the top of the Y-axis
    country_condition = fct_rev(fct_inorder(country_condition))
  ) |>
  # Optional: Clean up diff_type for better facet labels
  mutate(
    diff_type = factor(diff_type, levels = c("IF", "OD", "AP"))
  )


# 2. Create the Plot
ggplot(
  plot_data,
  aes(
    y = country_condition,
    x = Difference,
    shape = pid_type,
    color = meta_country
  )
) +

  # Add the vertical line at zero (to check for significance)
  geom_vline(xintercept = 0, linetype = "dashed", color = "red", alpha = 0.6) +

  # Add the Confidence Intervals (horizontal error bars)
  geom_errorbarh(
    aes(xmin = CI_LOWER, xmax = CI_UPPER),
    height = 0.2,
    linewidth = 0.5
  ) +

  # Add the point estimate
  geom_point(size = 2.5) +

  # Crucial Step: Facet the plot horizontally by the Difference Type (IF, OD, AP)
  facet_wrap(
    ~diff_type,
    ncol = 3,
    scales = "free_x" # Allow x-axis to scale independently for each difference type
  ) +

  # Labels and theming
  labs(
    y = "Country | PID Type",
    x = "Mean Difference (Point Estimate with 95% CI)"
  ) +
  theme_pubr() +
  scale_color_manual(
    values = rep(
      c(
        "#648FFF",
        "#DC267F",
        "#785EF0",
        "#FE6100",
        "#FFB000"
      ),
      5
    )
  ) +
  theme(
    # Reduce font size for Y-axis labels if they are too long
    axis.text.y = element_text(size = 8, hjust = 0),
    # Ensure facet titles are clear
    strip.text = element_text(face = "bold"),
    legend.position = "none"
  )
`height` was translated to `width`.
Exploratory token allocation behavior by country and pid type in the trust game: ingroup favoritism, outgroup derogation and affective polarization. The figure shows mean differences in token allocation with 95% confidence intervals. IF = mean(token2co) - mean(token2control), OD = mean(token2control) - mean(token2out), AP = mean(token2co) - mean(token2out)
In [26]:
Code

eu25games2019 |>
  tabyl(der_partisanship) |>
  adorn_totals()
 der_partisanship      n    percent valid_percent
       1_pid_expl 110142 0.61553852     0.6431199
       2_pid_impl  37418 0.20911387     0.2184840
          3_nopid  23702 0.13246077     0.1383961
             <NA>   7674 0.04288684            NA
            Total 178936 1.00000000     1.0000000
Code

eu25games2019 |>
  tabyl(der_outpartisan_comb) |>
  adorn_totals()
 der_outpartisan_comb      n     percent valid_percent
       1_control_expl  14898 0.083258819   0.086989525
            2_co_expl  30820 0.172240354   0.179958193
           3_out_expl  29366 0.164114544   0.171468277
       4_control_impl   5123 0.028630348   0.029913232
            5_co_impl   1948 0.010886574   0.011374385
           6_out_impl  18465 0.103193321   0.107817262
      7_control_nopid   3236 0.018084678   0.018895026
       8_ptycue_nopid  12878 0.071969866   0.075194731
        97_eunat_expl  19951 0.111497966   0.116494027
        97_eunat_impl   6809 0.038052712   0.039757798
       98_outnat_expl  15107 0.084426834   0.088209877
       98_outnat_impl   5073 0.028350919   0.029621282
    99_outnatEU_nopid   5936 0.033173872   0.034660345
      99_outnat_nopid   1652 0.009232351   0.009646039
                 <NA>   7674 0.042886842            NA
                Total 178936 1.000000000   1.000000000
In [27]:
Code

eu25games2019 |>
  tabyl(der_outpartisan_comb, meta_country) |>
  adorn_totals()
 der_outpartisan_comb Austria Belgium Bulgaria Croatia Czech Republic Denmark
       1_control_expl     517     688      371     505            644     798
            2_co_expl    1091    1442      751    1049           1401    1649
           3_out_expl    1076    1467      775    1018           1259    1636
       4_control_impl     370     208      198     176            124      79
            5_co_impl     169      69       94      58             57      29
           6_out_impl    1277     704      752     660            408     263
      7_control_nopid     119     122      122     223            138      57
       8_ptycue_nopid     499     478      497     842            517     256
        97_eunat_expl     728     971      487     665            882    1089
        97_eunat_impl     463     242      298     251            126      96
       98_outnat_expl     566     724      406     549            662     834
       98_outnat_impl     343     211      206     175            113      73
      99_outnat_nopid      62      55       73     115             68      24
    99_outnatEU_nopid     226     239      232     380            255     113
                 <NA>     156     210      630     774            156     204
                Total    7662    7830     5892    7440           6810    7200
 Estonia Finland France Germany Greece Hungary Ireland Italy Latvia Lithuania
     464     598    597     552    582     480     422   697    364       487
     896    1178   1239    1183   1199    1172     875  1563    742       882
     910    1166   1175    1049   1049     913     834  1366    733       903
     244     159    153     240    167     172     266    79    375       346
     122      96     65     104     38      48     124    40     48       114
     807     645    530     842    611     573     954   302   1376      1394
      42     134    166     138    134      95     134   126    119       146
     198     533    681     554    516     389     567   493    582       614
     594     797    837     721    796     733     539   972    473       622
     323     218    193     346    196     182     385   108    488       502
     454     623    598     557    568     536     414   748    364       454
     232     166    169     232    182     159     287    89    365       368
      28      66     81      70     54      50      58    70     85        92
      68     251    284     252    214     174     279   229    282       270
     282     330    168     288    660     240     228   150    492       396
    5664    6960   6936    7128   6966    5916    6366  7032   6888      7590
 Netherlands Poland Portugal Romania Slovakia Slovenia Spain Sweden
         679    728      628     662      610      604   806    726
        1374   1481     1162    1323     1253     1269  1698   1616
        1382   1332     1220    1352     1242     1114  1581   1486
         152    147      149     325      233      166   199    133
          61     49       40     175       78       56    50     59
         573    647      547    1127      798      598   701    455
         133    107      159     144      188      157   120     99
         523    368      691     625      731      506   410    371
         896    951      788     904      810      750  1055   1024
         246    229      201     416      298      230   248    175
         697    698      588     691      621      541   794    770
         150    170      137     281      225      174   188    144
          72     51       84      79       89       66    61     53
         232    170      288     290      342      249   213    185
         156     60      432     468      264      330   252    228
        7326   7188     7114    8862     7782     6810  8376   7524
 United Kingdom
            689
           1332
           1328
            263
            105
            921
            114
            437
            867
            349
            650
            234
             46
            219
            120
           7674
In [28]:
Code

eu25games2019 |>
  tabyl(der_partisan_type) |>
  adorn_totals() |>
  adorn_rounding() |>
  knitr::kable()
In [29]:
der_partisan_type n percent valid_percent
0 37418 0.2 0.3
1 110142 0.6 0.7
NA 31376 0.2 NA
Total 178936 1.0 1.0
Code

eu25games2019 |>
  tabyl(meta_country, der_partisan_type) |>
  adorn_totals()
In [30]:
   meta_country     0      1   NA_
        Austria  2622   3978  1062
        Belgium  1434   5292  1104
       Bulgaria  1548   2790  1554
        Croatia  1320   3786  2334
 Czech Republic   828   4848  1134
        Denmark   540   6006   654
        Estonia  1728   3318   618
        Finland  1284   4362  1314
         France  1110   4446  1380
        Germany  1764   4062  1302
         Greece  1194   4194  1578
        Hungary  1134   3834   948
        Ireland  2016   3084  1266
          Italy   618   5346  1068
         Latvia  2652   2676  1560
      Lithuania  2724   3348  1518
    Netherlands  1182   5028  1116
         Poland  1242   5190   756
       Portugal  1074   4386  1654
        Romania  2324   4932  1606
       Slovakia  1632   4536  1614
       Slovenia  1224   4278  1308
          Spain  1386   5934  1056
         Sweden   966   5622   936
 United Kingdom  1872   4866   936
          Total 37418 110142 31376
Code

eu25games2019 |>
  filter(meta_country == "Austria") |>
  tabyl(der_partisan_anchor) |>
  adorn_totals() |>
  adorn_rounding()
In [31]:
                                der_partisan_anchor    n percent valid_percent
                 Die Grünen — Die grüne Alternative  834     0.1           0.1
                     EU-Austrittspartei (EUAUS)[og]   42     0.0           0.0
 EUROPA Jetzt – Initiative Johannes Voggenhuber[og]   60     0.0           0.0
                   Freiheitliche Partei Österreichs 1470     0.2           0.2
         KPÖ Plus – European Left, offene Liste[og]   60     0.0           0.0
                  Kommunistische Partei Österreichs   84     0.0           0.0
                                   Liste Peter Pilz   78     0.0           0.0
                         NEOS — Das Neue Österreich  696     0.1           0.1
                                        Piraten[og]   30     0.0           0.0
             Sozialdemokratische Partei Österreichs 1620     0.2           0.2
                        Österreichische Volkspartei 1626     0.2           0.2
                                               <NA> 1062     0.1            NA
                                              Total 7662     1.0           1.0
Code

eu25games2019 |>
  filter(meta_country == "Austria") |>
  tabyl(der_partisan_anchor, der_partisan_type)
In [32]:
                                der_partisan_anchor   0    1  NA_
                 Die Grünen — Die grüne Alternative 390  444    0
                     EU-Austrittspartei (EUAUS)[og]   0   42    0
 EUROPA Jetzt – Initiative Johannes Voggenhuber[og]  60    0    0
                   Freiheitliche Partei Österreichs 504  966    0
                  Kommunistische Partei Österreichs   0   84    0
         KPÖ Plus – European Left, offene Liste[og]  60    0    0
                                   Liste Peter Pilz   0   78    0
                         NEOS — Das Neue Österreich 474  222    0
                        Österreichische Volkspartei 576 1050    0
                                        Piraten[og]   0   30    0
             Sozialdemokratische Partei Österreichs 558 1062    0
                                               <NA>   0    0 1062
Code

eu25games2019 |>
  tabyl(der_partisan_relationship) |>
  adorn_totals() |>
  adorn_rounding()
In [33]:
 der_partisan_relationship      n percent valid_percent
                      None  24326     0.1           0.2
                        Co  51837     0.3           0.3
                       Out  75694     0.4           0.5
                      <NA>  27079     0.2            NA
                     Total 178936     1.0           1.0
Code

eu25games2019 |>
  tabyl(der_partisan_relationship, der_partisan_type)
In [34]:
 der_partisan_relationship     0     1   NA_
                      None  5123 14898  4305
                        Co  3046 48791     0
                       Out 29241 46453     0
                      <NA>     8     0 27071

DESCRIPTIVE SUMMARY STATISTICS

Table respondents by country

In [35]:
Code

eu25games2019 |>
  distinct(meta_pid, .keep_all = T) |>
  tabyl(
    meta_country
  ) |>
  adorn_rounding(2) |>
  adorn_totals() |>
  knitr::kable(col.names = c("Country", "N", "Percent"))
In [36]:
Sample composition by country. Numbers denote respondents.
Country N Percent
Austria 1277 0.04
Belgium 1305 0.04
Bulgaria 982 0.03
Croatia 1240 0.04
Czech Republic 1135 0.04
Denmark 1200 0.04
Estonia 944 0.03
Finland 1160 0.04
France 1156 0.04
Germany 1188 0.04
Greece 1161 0.04
Hungary 986 0.03
Ireland 1061 0.04
Italy 1172 0.04
Latvia 1148 0.04
Lithuania 1265 0.04
Netherlands 1221 0.04
Poland 1198 0.04
Portugal 1187 0.04
Romania 1480 0.05
Slovakia 1297 0.04
Slovenia 1135 0.04
Spain 1396 0.05
Sweden 1254 0.04
United Kingdom 1279 0.04
Total 29827 0.99

Table respondents by country and gender

In [37]:
Code

eu25games2019 |>
  distinct(meta_pid, .keep_all = T) |>
  tabyl(
    meta_country,
    q_gender
  ) |>
  adorn_totals() |>
  knitr::kable(
    col.names = c("Country", "Male", "Female", "Other")
  )
In [38]:
Sample composition by country and gender. Numbers denote respondents.
Country Male Female Other
Austria 645 630 2
Belgium 729 574 2
Bulgaria 463 518 1
Croatia 545 694 1
Czech Republic 515 618 2
Denmark 690 508 2
Estonia 331 611 2
Finland 586 567 7
France 562 594 0
Germany 587 597 4
Greece 588 572 1
Hungary 493 492 1
Ireland 481 577 3
Italy 603 569 0
Latvia 415 733 0
Lithuania 462 803 0
Netherlands 642 577 2
Poland 540 658 0
Portugal 593 593 1
Romania 837 641 2
Slovakia 550 746 1
Slovenia 569 566 0
Spain 677 718 1
Sweden 648 602 4
United Kingdom 635 641 3
Total 14386 15399 42

Table respondents by country and age group

In [39]:
Code

eu25games2019 |>
  distinct(meta_pid, .keep_all = TRUE) |>
  group_by(meta_country) |>
  summarise(
    `18-25` = sum(q_age >= 18 & q_age <= 25, na.rm = T),
    `26-35` = sum(q_age >= 26 & q_age <= 35, na.rm = T),
    `36-45` = sum(q_age >= 36 & q_age <= 45, na.rm = T),
    `46-55` = sum(q_age >= 46 & q_age <= 55, na.rm = T),
    `56-65` = sum(q_age >= 56 & q_age <= 65, na.rm = T),
    `66-75` = sum(q_age >= 66 & q_age <= 75, na.rm = T),
    `>76` = sum(q_age >= 76, na.rm = T)
  ) |>
  adorn_totals() |>
  knitr::kable(
    col.names = c(
      "Country",
      "18 to 25",
      "26 to 35",
      "36 to 45",
      "46 to 55",
      "56 to 65",
      "66 to 75",
      "> 75"
    )
  )
In [40]:
Sample composition by country and age group. Numbers denote respondents.
Country 18 to 25 26 to 35 36 to 45 46 to 55 56 to 65 66 to 75 > 75
Austria 144 177 249 263 286 142 0
Belgium 197 132 160 235 333 239 3
Bulgaria 57 195 231 250 212 33 0
Croatia 119 251 272 331 205 47 0
Czech Republic 88 187 227 219 281 126 0
Denmark 132 134 139 208 321 249 4
Estonia 56 168 164 283 265 7 0
Finland 125 178 210 242 259 137 1
France 123 176 242 267 279 51 0
Germany 125 184 200 240 313 117 0
Greece 77 202 376 318 136 34 0
Hungary 51 175 196 166 273 117 1
Ireland 128 216 223 187 169 120 0
Italy 104 196 264 195 294 98 2
Latvia 78 251 231 338 239 6 0
Lithuania 223 311 257 250 212 2 0
Netherlands 149 126 161 234 340 194 3
Poland 200 342 222 187 196 42 0
Portugal 112 260 289 231 218 67 1
Romania 128 339 373 347 202 65 0
Slovakia 139 223 282 290 250 108 1
Slovenia 97 186 246 284 234 72 0
Spain 125 293 355 305 228 66 1
Sweden 124 165 156 234 297 261 3
United Kingdom 121 184 196 234 268 250 1
Total 3022 5251 5921 6338 6310 2650 21

Model DAG

In [41]:
Code

dag <- dagitty(
  "dag {
\"Z1\" [pos=\"0, 1\"]
A [pos=\"0, 2\"]
C [pos=\"2, 1\"]
R [pos=\"1 ,1\"]
T [exposure,pos=\"1 , 2\"]
Y [outcome,pos=\"1 ,0\"]
Z [pos=\"0 ,0\"]
\"Z1\" -> R
A -> R
A -> T
C -> T
C -> Y
R -> Y
T -> R
Z -> Y
}"
)

tidy_dag <- tidy_dagitty(dag)

label_mapping <- tibble(
  name = c("A", "C", "R", "T", "Y", "Z", "Z1"),
  new_label = c(
    "italic(A[i])", # partisan anchor of respondent i
    "italic(C[i])", # respondent confounders
    "italic(R[ri])", # relationship (round r, respondent i)
    "italic(T[i])", # partisan type of respondent i
    "italic(Y[riac])", # tokens (r,i,a,c)
    "italic(Z[r]^{other})", # other randomized cues (round r)
    "italic(Z[r]^{party})" # party cue shown in round r
  )
)

tidy_dag <- tidy_dag |>
  left_join(
    label_mapping,
    by = join_by(name)
  )

ggdag(tidy_dag) +
  geom_dag_node() +
  geom_dag_text(aes(label = new_label), parse = T) +
  geom_dag_edges() +
  theme_dag() +
  theme(
    aspect.ratio = 1 / 1.618034
  )
Directed acyclic graph of the causal data-generating process. Respondents have a partisan anchor \(A_i\), representing the party they feel attached to (explicit partisans) or intend to vote for (implicit partisans). Partisan type \(T_i\) (explicit vs. implicit) is only defined for respondents with a partisan anchor and is therefore a child node of \(A_i\). Each conjoint profile shown in round \(r\) presents randomized attributes: a partisan cue \(Z^{party}_r\) and other attributes \(Z^{other}_r\). The partisan-relationship variable \(R_{ri} = f(A_i, Z^{party}_r)\) determines whether the profile is interpreted as a co-partisan, out-partisan, or neutral for respondent \(i\). Token allocations \(Y_{riac}\) are affected by both \(R_{ri}\) and \(Z^{other}_r\), with the effect of \(R_{ri}\) theorized to depend on \(T_i\). Because \(T_i\) is observational, \(C_i\) denotes potential confounders of both \(T_i\) and \(Y_{ri}\), highlighting the assumptions required for causal interpretation.

Model data

In [42]:
Code

df_modelvars <- eu25games2019 |>
  filter(
    der_conational == "co-national",
    !is.na(der_partisan_type)
  ) |>
  select(
    # outcome Y
    cj_token,
    # vars of interest
    der_partisan_type, # T
    der_partisan_relationship, # R
    # identifiers/hierarchical groupings
    meta_pid,
    der_partisan_anchor,
    meta_country,
    # game variables
    meta_game,
    meta_game_lab,
    # conjoint controls Z
    meta_round,
    meta_wave,
    cj_age_en,
    cj_reli_en,
    cj_class_en,
    cj_sex_en,
    cj_eupos_shown,
    # =========================================================================
    # COVARIATES (C) FOR CAUSAL ISOLATION
    # =========================================================================

    # --- BLOCK 1: Fundamental Political Identity and Ideology (Core Drivers of T & Y) ---
    q_lrpos2, # Left-Right ideological self-placement (Controls for core political position)
    q_eupos2, # EU integration position (Controls for major second dimension position)
    q_econ_nativism, # Attitudes towards economic nativism (Controls for key sociotropic threat perception)
    q_cult_nativism, # Attitudes towards cultural nativism (Controls for key sociotropic identity boundary)
    q_religion_en, # Respondent's religious affiliation (Controls for a major social cleavage/identity)

    # --- BLOCK 2: Anti-System & Populist Attitudes (CRUCIAL CONFOUNDERS for T) ---
    # These variables control for system-level dissatisfaction/cynicism that pushes
    # individuals to reject EXPLICIT partisan identity (T=0) while also driving Y.
    q_satis_demo_country, # Satisfaction with democracy in the country (System trust)
    q_understand_nat_pol, # Political efficacy (national level)
    q_nat_politicians_care, # Political responsiveness (national level)
    q_nat_public_say, # Political efficacy (national level)
    q_understand_eu_pol, # Political efficacy (EU level)
    q_eu_politicians_care, # Political responsiveness (EU level)
    q_eu_public_say, # Political efficacy (EU level)
    q_parties_harm, # Anti-party sentiment ("Parties do more harm than good")
    q_officials_talk_action, # Anti-elitism ("Officials talk too much")
    q_prefer_citizen_rep, # People-centrism ("Prefer citizens to politicians")
    q_people_make_decisions, # People-centrism ("People, not politicians, should decide")
    q_politicians_follow_people, # People-centrism ("Politicians must follow the people's will")
    q_politics_good_evil, # Manichaean worldview ("Politics is good vs. evil")
    q_people_unaware, # System cynicism ("People are unaware")
    q_leaders_educated, # Anti-populism (Elitism)
    q_expert_decisions, # Anti-populism (Expert governance)
    q_listen_other_groups, # Tolerance/Pluralism
    q_democracy_compromise, # Tolerance/Pluralism

    # --- BLOCK 3: Political Engagement & General Identity (Predictors of T and Y) ---
    q_attach_country, # Emotional attachment to one's country
    q_attach_eu, # Emotional attachment to the EU
    q_attach_eur, # Emotional attachment to Europe
    q_interest_pol_country, # Political engagement (national)
    q_interest_pol_eu, # Political engagement (EU)
    q_election_importance, # Political engagement (election importance)

    # --- BLOCK 4: Socioeconomic Status (SES) and Economic Context (Background Predictors) ---
    q_edu, # Education level
    q_perc_class, # Subjective social class
    q_eval_finance_household, # Micro-level economic evaluation
    q_eval_job, # Job/Employment evaluation
    q_eval_econ_country, # Macro-level economic evaluation (country)
    q_eval_econ_eur, # Macro-level economic evaluation (Europe)

    # --- BLOCK 5: Demographics and Fixed Traits (General Controls) ---
    q_gender, # Respondent's gender
    q_age, # Respondent's age
    q_rural_urban, # Residence setting
    q_risk_taking, # General propensity for risk-taking behavior
    q_future_discount # Patience/future discounting trait
  )


na_counts_modelvars1 <- df_modelvars |>
  # 1. Summarise: Calculate the sum of NAs for every column.
  summarise(across(
    .cols = everything(),
    .fns = ~ sum(is.na(.)),
    .names = "na_count_{.col}" # Temporarily rename columns for pivot
  )) |>

  # 2. Pivot: Convert the wide one-row summary into a tall, two-column table.
  pivot_longer(
    cols = everything(),
    names_to = "Variable",
    values_to = "NA_Count"
  ) |>

  # 3. Clean: Remove the temporary prefix for cleaner variable names.
  mutate(Variable = str_remove(Variable, "na_count_")) |>

  # 4. Arrange: Sort the result to see the variables with the most NAs first.
  arrange(desc(NA_Count))


# Remove variables with too many NAs (>10k)
df_modelvars <- df_modelvars |>
  select(
    -q_nat_politicians_care,
    -q_nat_public_say,
    -q_eu_politicians_care,
    -q_eu_public_say,
    -q_prefer_citizen_rep,
    -q_people_make_decisions,
    -q_politicians_follow_people,
    -q_attach_country,
    -q_attach_eu,
    -q_attach_eur,
    -q_election_importance
  )

# Recode dont know answers correctly
df_modelvars <- df_modelvars |>
  mutate(
    q_satis_demo_country = case_when(
      q_satis_demo_country == 5 | q_satis_demo_country == 6 ~ NA,
      .default = q_satis_demo_country
    ),
    q_perc_class = if_else(
      q_perc_class == 6,
      NA,
      q_perc_class
    ),
    q_eval_finance_household = if_else(
      q_eval_finance_household == 6,
      NA,
      q_eval_finance_household
    ),
    q_eval_job = if_else(
      q_eval_job == 6,
      NA,
      q_eval_job
    ),
    q_eval_econ_country = if_else(
      q_eval_econ_country == 6,
      NA,
      q_eval_econ_country
    ),
    q_eval_econ_eur = if_else(
      q_eval_econ_eur == 6,
      NA,
      q_eval_econ_eur
    ),
    q_rural_urban = if_else(
      q_rural_urban == 4,
      NA,
      q_rural_urban
    )
  )

# Categeorical to factors
df_modelvars <- df_modelvars |>
  mutate(
    # categorical to factors
    q_perc_class = factor(
      q_perc_class,
      levels = c(1, 2, 3, 4, 5),
      labels = c(
        "Working class",
        "Lower middle class",
        "Middle class",
        "Upper middle class",
        "Upper class"
      )
    ),
    q_rural_urban = factor(
      q_rural_urban,
      levels = c(1, 2, 3),
      labels = c(
        "Rural area or village",
        "Small or middle sized town",
        "Large town"
      )
    ),
    q_gender = factor(
      q_gender,
      levels = c(1, 2, 3),
      labels = c("Male", "Female", "Other")
    ),
    q_religion_en = as_factor(q_religion_en)
  )

# standardize survey scales
df_modelvars <- df_modelvars |>
  mutate(
    across(
      .cols = c(
        q_lrpos2,
        q_eupos2,
        q_econ_nativism,
        q_cult_nativism,
        q_satis_demo_country,
        q_understand_nat_pol,
        q_understand_eu_pol,
        q_parties_harm,
        q_officials_talk_action,
        q_politics_good_evil,
        q_people_unaware,
        q_leaders_educated,
        q_expert_decisions,
        q_listen_other_groups,
        q_democracy_compromise,
        q_interest_pol_country,
        q_interest_pol_eu,
        q_eval_finance_household,
        q_eval_job,
        q_eval_econ_country,
        q_eval_econ_eur,
        q_risk_taking,
        q_future_discount,
        q_edu,
        q_age
      ), # List all continuous variables to standardize
      .fns = ~ scale(.)[, 1], # Apply the scale() function
      .names = "{.col}_z" # Name the new standardized columns with a '_z' suffix
    )
  )

# Check again how missings have changed
na_counts_modelvars2 <- df_modelvars |>
  # 1. Summarise: Calculate the sum of NAs for every column.
  summarise(across(
    .cols = everything(),
    .fns = ~ sum(is.na(.)),
    .names = "na_count_{.col}" # Temporarily rename columns for pivot
  )) |>

  # 2. Pivot: Convert the wide one-row summary into a tall, two-column table.
  pivot_longer(
    cols = everything(),
    names_to = "Variable",
    values_to = "NA_Count"
  ) |>

  # 3. Clean: Remove the temporary prefix for cleaner variable names.
  mutate(Variable = str_remove(Variable, "na_count_")) |>

  # 4. Arrange: Sort the result to see the variables with the most NAs first.
  arrange(desc(NA_Count))

# Global variable mapping and final df for modelling
df_modelvars <- df_modelvars |>
  select(
    starts_with("cj_"),
    starts_with("der_"),
    starts_with("meta_"),
    ends_with("_z"),
    q_religion_en,
    q_perc_class,
    q_rural_urban,
    q_gender
  )

modelvars_labels <- c(
  "Token" = "cj_token",
  "Conj. Age" = "cj_age_en",
  "Conj. Religion" = "cj_reli_en",
  "Conj. Class" = "cj_class_en",
  "Conj. Gender" = "cj_sex_en",
  "Conj. EU" = "cj_eupos_shown",
  "Type" = "der_partisan_type",
  "Relationship" = "der_partisan_relationship",
  "Anchor" = "der_partisan_anchor",
  "Resp. ID" = "meta_pid",
  "Country" = "meta_country",
  "Game" = "meta_game_lab",
  "Round" = "meta_round",
  "Wave" = "meta_wave",
  "LR Pos" = "q_lrpos2_z",
  "EU Pos" = "q_eupos2_z",
  "Econ. Nativism" = "q_econ_nativism_z",
  "Cult. Nativism" = "q_cult_nativism_z",
  "Satis. Democ." = "q_satis_demo_country_z",
  "Understand Nat. Pol." = "q_understand_nat_pol_z",
  "Understand EU Pol." = "q_understand_eu_pol_z",
  "Parties Harm" = "q_parties_harm_z",
  "Officials Talk/Action" = "q_officials_talk_action_z",
  "Politics Good/Evil" = "q_politics_good_evil_z",
  "People Unaware" = "q_people_unaware_z",
  "Leaders Educated" = "q_leaders_educated_z",
  "Expert Decisions" = "q_expert_decisions_z",
  "Listen Other Groups" = "q_listen_other_groups_z",
  "Democ. Compromise" = "q_democracy_compromise_z",
  "Interest Nat. Pol." = "q_interest_pol_country_z",
  "Interest EU Pol." = "q_interest_pol_eu_z",
  "Eval. HH Finance" = "q_eval_finance_household_z",
  "Eval. Job" = "q_eval_job_z",
  "Eval. Nat. Econ." = "q_eval_econ_country_z",
  "Eval. Eur. Econ." = "q_eval_econ_eur_z",
  "Risk Taking" = "q_risk_taking_z",
  "Future Discount" = "q_future_discount_z",
  "Education (Z)" = "q_edu_z",
  "Age (Z)" = "q_age_z",
  "Religion" = "q_religion_en",
  "Perc. Class" = "q_perc_class",
  "Rural/Urban" = "q_rural_urban",
  "Gender" = "q_gender"
)

Distribution of DV

In [43]:
Code

summary_stats <- df_modelvars %>%
  group_by(meta_game_lab) %>%
  summarise(
    mean_token = mean(cj_token, na.rm = TRUE),
    median_token = median(cj_token, na.rm = TRUE),
    sd_token = sd(cj_token, na.rm = TRUE)
  )


df_modelvars |>
  select(cj_token, meta_game_lab) |>
  ggplot(
    aes(x = log(cj_token + 1), fill = meta_game_lab)
  ) +
  geom_histogram(
    position = position_dodge(),
    color = "black"
  ) +
  # scale_x_continuous(
  #   breaks = 0:10,
  #   labels = 0:10
  # ) +
  scale_fill_manual(
    values = c("white", "gray")
  ) +
  labs(
    x = "Tokens allocated (Y)",
    y = "N",
    fill = "Conjoint Game"
  ) +
  ggpubr::theme_pubr()
`stat_bin()` using `bins = 30`. Pick better value `binwidth`.
Distribution of token allocation (Y) by game. Dictator game: \(Mean = 3.41\), \(median = 4\), \(SD = 2.35\). Trust game: \(Mean = 3.48\), \(median = 4\), \(SD = 2.49\)

Distribution of partisan type \(T\) and relationship category \(R\)

In [44]:
Code

df_modelvars |>
  tabyl(der_partisan_type, der_partisan_relationship) |>
  gt()
In [45]:
der_partisan_type None Co Out
0 5123 1948 18465
1 14898 30820 29366

Covariate Distributions

In [46]:
Code

df_modelvars |>
  select(
    der_partisan_type,
    ends_with("_z"),
    q_religion_en,
    q_perc_class,
    q_rural_urban,
    q_gender
  ) |>
  tbl_summary(
    by = der_partisan_type,
    missing = "no",
    type = list(
      q_econ_nativism_z ~ "continuous",
      q_cult_nativism_z ~ "continuous",
      q_satis_demo_country_z ~ "continuous",
      q_understand_nat_pol_z ~ "continuous",
      q_understand_eu_pol_z ~ "continuous",
      q_parties_harm_z ~ "continuous",
      q_officials_talk_action_z ~ "continuous",
      q_politics_good_evil_z ~ "continuous",
      q_people_unaware_z ~ "continuous",
      q_leaders_educated_z ~ "continuous",
      q_expert_decisions_z ~ "continuous",
      q_listen_other_groups_z ~ "continuous",
      q_democracy_compromise_z ~ "continuous",
      q_interest_pol_country_z ~ "continuous",
      q_interest_pol_eu_z ~ "continuous",
      q_eval_finance_household_z ~ "continuous",
      q_eval_job_z ~ "continuous",
      q_eval_econ_country_z ~ "continuous",
      q_eval_econ_eur_z ~ "continuous",
      q_risk_taking_z ~ "continuous",
      q_future_discount_z ~ "continuous"
    )
  ) |>
  modify_header(label = "**Variable**") |>
  as_gt() |>
  tab_options(table.font.size = 10)
In [47]:
Variable 0
N = 25,5361
1
N = 75,0841
q_lrpos2_z -0.08 (-0.45, 0.29) -0.08 (-0.82, 0.66)
q_eupos2_z 0.08 (-0.68, 0.46) 0.08 (-0.68, 0.84)
q_econ_nativism_z 0.15 (-1.03, 0.74) 0.15 (-1.03, 0.74)
q_cult_nativism_z 0.07 (-1.03, 0.62) 0.07 (-1.03, 0.62)
q_satis_demo_country_z 0.30 (-0.81, 1.40) 0.30 (-0.81, 0.30)
q_understand_nat_pol_z 0.12 (-0.65, 0.12) 0.12 (-0.65, 0.90)
q_understand_eu_pol_z 0.22 (-0.50, 0.22) 0.22 (-0.50, 0.94)
q_parties_harm_z 0.25 (-0.38, 0.88) 0.25 (-0.38, 0.88)
q_officials_talk_action_z 0.41 (-0.33, 1.15) 0.41 (-0.33, 1.15)
q_politics_good_evil_z -0.14 (-0.76, 0.48) -0.14 (-0.76, 0.48)
q_people_unaware_z 0.40 (-0.81, 1.00) -0.20 (-0.81, 1.00)
q_leaders_educated_z 0.39 (-0.32, 1.10) 0.39 (-1.03, 1.10)
q_expert_decisions_z 0.16 (-0.49, 0.80) 0.16 (-0.49, 0.80)
q_listen_other_groups_z 0.18 (-0.74, 1.10) 0.18 (-0.74, 1.10)
q_democracy_compromise_z -0.29 (-0.29, 0.57) -0.29 (-0.29, 0.57)
q_interest_pol_country_z 0.06 (-0.60, 0.72) 0.06 (-0.60, 0.72)
q_interest_pol_eu_z -0.28 (-0.96, 0.39) 0.39 (-0.28, 1.06)
q_eval_finance_household_z 0.01 (-0.99, 1.00) 0.01 (-0.99, 1.00)
q_eval_job_z 0.11 (-0.80, 1.03) 0.11 (-0.80, 0.11)
q_eval_econ_country_z -0.14 (-1.03, 0.76) -0.14 (-1.03, 0.76)
q_eval_econ_eur_z 0.07 (-0.94, 1.09) 0.07 (-0.94, 1.09)
q_risk_taking_z 0.11 (-0.56, 0.78) 0.11 (-0.56, 0.78)
q_future_discount_z -0.17 (-0.84, 0.50) -0.17 (-0.84, 0.50)
q_edu_z -0.08 (-0.73, 0.57) -0.08 (-0.73, 0.57)
q_age_z -0.11 (-0.92, 0.64) 0.09 (-0.79, 0.91)
q_religion_en

    catholic 8,606 (34%) 27,379 (36%)
    no religion 9,462 (37%) 25,678 (34%)
    protstnt 1,881 (7.4%) 7,570 (10%)
    other religion 5,470 (21%) 13,791 (18%)
    muslim 114 (0.4%) 664 (0.9%)
q_perc_class

    Working class 5,307 (22%) 15,198 (21%)
    Lower middle class 4,866 (20%) 13,924 (19%)
    Middle class 12,060 (49%) 35,019 (48%)
    Upper middle class 2,055 (8.4%) 7,622 (10%)
    Upper class 191 (0.8%) 1,310 (1.8%)
q_rural_urban

    Rural area or village 5,819 (23%) 17,093 (23%)
    Small or middle sized town 9,069 (36%) 28,418 (38%)
    Large town 10,573 (42%) 29,298 (39%)
q_gender

    Male 10,939 (43%) 39,456 (53%)
    Female 14,565 (57%) 35,514 (47%)
    Other 32 (0.1%) 114 (0.2%)
1 Median (Q1, Q3); n (%)

Saving

In [48]:
Code

# save modeldata
save(
  df_modelvars,
  file = here("data", "02_processed", "df_modeldata.RData")
)

CONJOINT RANDOMIZATION CHECKS

Session Info

In [49]:
Code

session_info()
Warning in system2("quarto", "-V", stdout = TRUE, env = paste0("TMPDIR=", :
running command '"quarto"
TMPDIR=C:/Users/Tris/AppData/Local/Temp/RtmpkjsYK1/file5490353246f2 -V' had
status 1
─ Session info ───────────────────────────────────────────────────────────────
 setting  value
 version  R version 4.5.2 (2025-10-31 ucrt)
 os       Windows 11 x64 (build 26200)
 system   x86_64, mingw32
 ui       RTerm
 language (EN)
 collate  English_United States.utf8
 ctype    English_United States.utf8
 tz       Europe/Berlin
 date     2026-01-27
 pandoc   3.6.3 @ c:\\Program Files\\Positron\\resources\\app\\quarto\\bin\\tools/ (via rmarkdown)
 quarto   NA @ C:\\PROGRA~1\\Positron\\RESOUR~1\\app\\quarto\\bin\\quarto.exe

─ Packages ───────────────────────────────────────────────────────────────────
 ! package      * version date (UTC) lib source
 P abind          1.4-8   2024-09-12 [?] CRAN (R 4.5.0)
 P backports      1.5.0   2024-05-23 [?] CRAN (R 4.5.0)
 P base64enc      0.1-3   2015-07-28 [?] CRAN (R 4.5.0)
 P boot           1.3-32  2025-08-29 [?] CRAN (R 4.5.2)
 P broom          1.0.11  2025-12-04 [?] CRAN (R 4.5.2)
 P cachem         1.1.0   2024-05-16 [?] CRAN (R 4.5.1)
 P car            3.1-3   2024-09-27 [?] CRAN (R 4.5.1)
 P carData        3.0-5   2022-01-06 [?] CRAN (R 4.5.1)
 P cards          0.7.1   2025-12-02 [?] CRAN (R 4.5.2)
 P cli            3.6.5   2025-04-23 [?] CRAN (R 4.5.1)
 P commonmark     2.0.0   2025-07-07 [?] CRAN (R 4.5.2)
 P curl           7.0.0   2025-08-19 [?] CRAN (R 4.5.2)
 P dagitty      * 0.3-4   2023-12-07 [?] CRAN (R 4.5.2)
 P digest         0.6.39  2025-11-19 [?] CRAN (R 4.5.2)
 P dplyr        * 1.1.4   2023-11-17 [?] CRAN (R 4.5.1)
 P evaluate       1.0.5   2025-08-27 [?] CRAN (R 4.5.2)
 P farver         2.1.2   2024-05-13 [?] CRAN (R 4.5.1)
 P fastmap        1.2.0   2024-05-15 [?] CRAN (R 4.5.1)
 P forcats      * 1.0.1   2025-09-25 [?] CRAN (R 4.5.2)
 P Formula        1.2-5   2023-02-24 [?] CRAN (R 4.5.0)
 P fs             1.6.6   2025-04-12 [?] CRAN (R 4.5.1)
 P generics       0.1.4   2025-05-09 [?] CRAN (R 4.5.1)
 P ggdag        * 0.2.13  2024-07-22 [?] CRAN (R 4.5.2)
 P ggforce        0.5.0   2025-06-18 [?] CRAN (R 4.5.2)
 P ggplot2      * 4.0.1   2025-11-14 [?] CRAN (R 4.5.2)
 P ggpubr       * 0.6.2   2025-10-17 [?] CRAN (R 4.5.2)
 P ggraph         2.2.2   2025-08-24 [?] CRAN (R 4.5.2)
 P ggrepel        0.9.6   2024-09-07 [?] CRAN (R 4.5.1)
 P ggsignif       0.6.4   2022-10-13 [?] CRAN (R 4.5.1)
 P glue           1.8.0   2024-09-30 [?] CRAN (R 4.5.1)
 P graphlayouts   1.2.2   2025-01-23 [?] CRAN (R 4.5.2)
 P gridExtra      2.3     2017-09-09 [?] CRAN (R 4.5.1)
 P gt           * 1.2.0   2025-12-16 [?] CRAN (R 4.5.2)
 P gtable         0.3.6   2024-10-25 [?] CRAN (R 4.5.1)
 P gtsummary    * 2.5.0   2025-12-05 [?] CRAN (R 4.5.2)
 P here         * 1.0.2   2025-09-15 [?] CRAN (R 4.5.2)
 P hms            1.1.4   2025-10-17 [?] CRAN (R 4.5.2)
 P htmltools      0.5.9   2025-12-04 [?] CRAN (R 4.5.2)
 P htmlwidgets    1.6.4   2023-12-06 [?] CRAN (R 4.5.2)
 P igraph         2.2.1   2025-10-27 [?] CRAN (R 4.5.2)
 P janitor      * 2.2.1   2024-12-22 [?] CRAN (R 4.5.2)
 P jsonlite       2.0.0   2025-03-27 [?] CRAN (R 4.5.1)
 P knitr        * 1.51    2025-12-20 [?] CRAN (R 4.5.2)
 P labeling       0.4.3   2023-08-29 [?] CRAN (R 4.5.0)
 P lifecycle      1.0.5   2026-01-08 [?] CRAN (R 4.5.2)
 P litedown       0.9     2025-12-18 [?] CRAN (R 4.5.2)
 P lubridate    * 1.9.4   2024-12-08 [?] CRAN (R 4.5.1)
 P magrittr       2.0.4   2025-09-12 [?] CRAN (R 4.5.2)
 P markdown       2.0     2025-03-23 [?] CRAN (R 4.5.2)
 P MASS           7.3-65  2025-02-28 [?] CRAN (R 4.5.2)
 P memoise        2.0.1   2021-11-26 [?] CRAN (R 4.5.1)
 P pillar         1.11.1  2025-09-17 [?] CRAN (R 4.5.2)
 P pkgconfig      2.0.3   2019-09-22 [?] CRAN (R 4.5.1)
 P polyclip       1.10-7  2024-07-23 [?] CRAN (R 4.5.2)
 P purrr        * 1.2.1   2026-01-09 [?] CRAN (R 4.5.2)
 P R6             2.6.1   2025-02-15 [?] CRAN (R 4.5.1)
 P ragg           1.5.0   2025-09-02 [?] CRAN (R 4.5.2)
 P RColorBrewer   1.1-3   2022-04-03 [?] CRAN (R 4.5.0)
 P Rcpp           1.1.1   2026-01-10 [?] CRAN (R 4.5.2)
 P readr        * 2.1.6   2025-11-14 [?] CRAN (R 4.5.2)
   renv           1.1.5   2025-07-24 [1] CRAN (R 4.5.2)
 P rlang          1.1.7   2026-01-09 [?] CRAN (R 4.5.2)
 P rmarkdown      2.30    2025-09-28 [?] CRAN (R 4.5.2)
 P rprojroot      2.1.1   2025-08-26 [?] CRAN (R 4.5.2)
 P rstatix        0.7.3   2025-10-18 [?] CRAN (R 4.5.2)
 P S7             0.2.1   2025-11-14 [?] CRAN (R 4.5.2)
 P sass           0.4.10  2025-04-11 [?] CRAN (R 4.5.1)
 P scales       * 1.4.0   2025-04-24 [?] CRAN (R 4.5.1)
 P sessioninfo  * 1.2.3   2025-02-05 [?] CRAN (R 4.5.2)
 P snakecase      0.11.1  2023-08-27 [?] CRAN (R 4.5.2)
 P stringi        1.8.7   2025-03-27 [?] CRAN (R 4.5.0)
 P stringr      * 1.6.0   2025-11-04 [?] CRAN (R 4.5.2)
 P systemfonts    1.3.1   2025-10-01 [?] CRAN (R 4.5.1)
 P textshaping    1.0.4   2025-10-10 [?] CRAN (R 4.5.2)
 P tibble       * 3.3.1   2026-01-11 [?] CRAN (R 4.5.2)
 P tidygraph      1.3.1   2024-01-30 [?] CRAN (R 4.5.2)
 P tidyr        * 1.3.2   2025-12-19 [?] CRAN (R 4.5.2)
 P tidyselect     1.2.1   2024-03-11 [?] CRAN (R 4.5.1)
 P tidyverse    * 2.0.0   2023-02-22 [?] CRAN (R 4.5.1)
 P timechange     0.3.0   2024-01-18 [?] CRAN (R 4.5.1)
 P tweenr         2.0.3   2024-02-26 [?] CRAN (R 4.5.2)
 P tzdb           0.5.0   2025-03-15 [?] CRAN (R 4.5.1)
 P utf8           1.2.6   2025-06-08 [?] CRAN (R 4.5.1)
 P V8             8.0.1   2025-10-10 [?] CRAN (R 4.5.2)
 P vctrs          0.7.0   2026-01-16 [?] CRAN (R 4.5.2)
 P viridis        0.6.5   2024-01-29 [?] CRAN (R 4.5.2)
 P viridisLite    0.4.2   2023-05-02 [?] CRAN (R 4.5.1)
 P withr          3.0.2   2024-10-28 [?] CRAN (R 4.5.1)
 P xfun           0.55    2025-12-16 [?] CRAN (R 4.5.2)
 P xml2           1.5.1   2025-12-01 [?] CRAN (R 4.5.2)
 P yaml           2.3.12  2025-12-10 [?] CRAN (R 4.5.2)

 [1] C:/R/research/CSAP/renv/library/windows/R-4.5/x86_64-w64-mingw32
 [2] C:/Users/Tris/AppData/Local/R/cache/R/renv/sandbox/windows/R-4.5/x86_64-w64-mingw32/ebc25411

 * ── Packages attached to the search path.
 P ── Loaded and on-disk path mismatch.

──────────────────────────────────────────────────────────────────────────────

Render Time

In [50]:
Code

end_time <- Sys.time()

rendering_time <- end_time - start_time

message(paste(
  "Document rendered in:",
  round(as.numeric(rendering_time, units = "secs"), 2),
  "seconds.
"
))
Document rendered in: 46.43 seconds.